#UI.py -- handles the drawing and keypresses of various screens
import libtcodpy as L
import os,sys
import traceback
from Commons import *
from Map import *
from Creature import *
from AreaSelector import *

pausescreen,drawscreen,playerscreen = 0,0,0#set variables equal to 0

class StatusScreen:
	string = 'Test'
	def __init__(self):#initialize the screen
		self.s = L.console_new(len(self.string),1)#constant pause screen
		L.console_set_background_color(self.s,color_dark_purple)
		L.console_set_foreground_color(self.s,color_gold)
		L.console_clear(self.s)
		L.console_print_left(self.s,0,0,L.BKGND_NONE,self.string)
	def blitScreen(self):#blit the screen
		L.console_blit(self.s,0,0,len(self.string),1,0,0,0,1.0,1.0)
class PauseScreen(StatusScreen):#makes a constant pause screen
	string = '=PAUSED='	

class DrawScreen(StatusScreen):#makes a constant draw screen
	string = '=DRAWING='

class PlayerScreen(StatusScreen):#makes a player screen
	string = '=POSSESION='

class WizardTowerRL(State):#the game
	def __init__(self):
		self.attach(A_RNG,rng(L.random_get_instance()))
	def load(self,filename):#loads file, returns whether load is successful
		if (os.path.isfile(filename)):
			try:
				if (self.load_body(filename) == True):
					return True#successful
				else:
					PauseConsoleErrorScreen(self.load_body(filename))#pause the console
					Game()[A_UI_SWITCH](UI_TITLE)#switch to the title screen
				return False#not successful
			except Exception:#if the file could not be loaded for any reason not covered
				print "Error, could not load file from an unknown error!"
				traceback.print_exc()
				PauseConsoleErrorScreen("The file "+ str(filename) + " could not be loaded, due to an unknown error.  Please report the bug.")
				Game()[A_UI_SWITCH](UI_TITLE)#switch to the title screen
				return False#not successful
	def load_body(self,filename):#body of load function -- return a string with the message if there is an error, and True otherwise
		L.console_set_foreground_color(0,L.white)#load screen
	 	L.console_print_left(0,0,0,0,"Loading Map...")
		L.console_flush()
		try:#try to open the file
			fileObj = open(filename,"r")
		except IOError:#possible error on machine
			return "The save file " + str(filename) + " could not be read from!  Please check the permissions of the file, and make sure you can write to the file!"
		data = fileObj.read()
		if (data.count("\\ENDSECTION\n") <= 0):#to prevent bugs from zero ENDSECTIONs
			data = [data]
		else:
			data = data.split("\\ENDSECTION\n")#split the data by sections
		fileObj.close()
		m = Map(1,1)#make a map
		self.attach(A_MAP,m)#attach the map
		try:
			m.load(data[0])#load data
		except Exception:
			traceback.print_exc()#print the error
			return "The save file " + str(filename) + " has data that is not recognized by the program.  The data may have been corrupted."
		
		
		myview = MapViewer(Game()[A_MAP])#create the mapviewer
		myview.load(data[1])
		self.attach(A_MAP_VIEW, myview)
		self.loadedfile = filename#set the loaded file
		os.remove(filename)#remove the file
		return True#success!

setState(WizardTowerRL())
class TitleScreen(UIReader):#The title screen
	rendermap = False
	def __init__(self):
		self.choicenum = 0#cursor
		self.choices = ["Start Game","Load Game","Key Bindings","Quit"]#choices
		#choiceactions -- handles which choice leads to which function
		self.choiceactions = {"Start Game":self.start_game, "Load Game":self.load_game, "Key Bindings":self.key_bindings, "Quit":self.quit}
		L.console_credits_reset()
		self.endCredits = False
	def receiveUI(self,keypressed,keyreleased,mouse):#receive the ui
		if (not self.endCredits):#credits
			self.endCredits = L.console_credits_render(0,SCREEN_HEIGHT-7,True)
		L.console_set_background_color(0,L.Color(102,0,102))#purple
		L.console_set_foreground_color(0,L.Color(255,215,0))#gold
		L.console_print_center(0,SCREEN_WIDTH/2,0,0,"Wizard's Tower")
		startprint = 2
		for key in self.choices:#display the choices
			L.console_print_center(0,SCREEN_WIDTH/2,startprint,0,key)
			startprint += 1#for loop within
		L.console_set_char(0,SCREEN_WIDTH/2-(len(self.choices[self.choicenum])/2)-1,self.choicenum+2,174)#border the selection
		L.console_set_char(0,SCREEN_WIDTH/2+(len(self.choices[self.choicenum])/2)+(len(self.choices[self.choicenum])%2),self.choicenum+2,175)
		#scrolling and selection
		if (keyCommand("Menu Down")):
			self.choicenum += 1
			if (self.choicenum >= len(self.choices)):
				self.choicenum = 0
		if (keyCommand("Menu Up")):
			self.choicenum -= 1
			if (self.choicenum < 0):
				self.choicenum = len(self.choices)-1
		elif (keyCommand("Menu Select")):
			if (self.choiceactions[self.choices[self.choicenum]] != None):
				self.choiceactions[self.choices[self.choicenum]]()
				return
	def quit(self):
		sys.exit(1)

	def start_game(self):
		Game()[A_UI_SWITCH](UI_MAP)
	def load_game(self):
		Game()[A_UI_SWITCH](UI_LOAD)
	def key_bindings(self):
		Game()[A_UI_SWITCH](UI_KEY_BIND)
	def getUIConstant(self):
		return UI_TITLE


class LoadScreen(UIReader):#load screen, similar to the title screen
	rendermap = False
	def __init__(self,savedirectories):
		self.selector = 0
		L.console_set_background_color(0,L.Color(102,0,102))#purple
		L.console_set_foreground_color(0,L.Color(255,215,0))
		self.choicenum = 0
		self.choices = savedirectories
	def receiveUI(self,keypressed,keyreleased,mouse):
		L.console_print_center(0,SCREEN_WIDTH/2,0,0,"Choose a file to load:")
		startprint = 2
		for key in self.choices:
			L.console_print_center(0,SCREEN_WIDTH/2,startprint,0,key)
			startprint += 1#for loop within
		L.console_set_char(0,SCREEN_WIDTH/2-(len(self.choices[self.choicenum])/2)-1,self.choicenum+2,174)#border
		L.console_set_char(0,SCREEN_WIDTH/2+(len(self.choices[self.choicenum])/2)+(len(self.choices[self.choicenum])%2),self.choicenum+2,175)
		if (keyCommand("Menu Down")):
			self.choicenum += 1
			if (self.choicenum >= len(self.choices)):
				self.choicenum = 0
		elif (keyCommand("Menu Up")):
			self.choicenum -= 1
			if (self.choicenum < 0):
				self.choicenum = len(self.choices)-1
		elif (keyCommand("Menu Select")):
			Game()[A_UI_SWITCH](UI_MAP,SAVEFILE_PATH+self.choices[self.choicenum])
		elif (keyCommand("Menu Back")):
			Game()[A_UI_SWITCH](UI_TITLE)
	def getUIConstant(self):
		return UI_LOAD


def fill(theobject,x,y):#do a fill
	Game()[A_MAP][L_TILES][x][y] = Floor()
def wall(theobject,x,y):#do a wall
	Game()[A_MAP][L_TILES][x][y] = Wall()
def isbuilt(theobject,x,y):#can we make a selection here?
	xp = x + theobject.x1
	yp = y + theobject.y1
	if (xp < 1 or xp >= MAP_WIDTH-1 or yp < 1 or yp >= MAP_HEIGHT-1):#out of bounds
		return False
	for room in Game()[A_MAP_VIEW].completedroomselections:
		if (room.selectingArea(xp,yp)):#if selecting the area
			return False
	return Game()[A_MAP][L_TILES][xp][yp].isBuildable()
class CreatureUI(UIReader):#the UI when directly controlling a creature
	cansave = True
	def __init__(self,creature):
		Game()[A_MAP_VIEW].scrolltoXY(creature.x-SCREEN_WIDTH/2,creature.y-SCREEN_HEIGHT/2)#zoom to the player
		Game()[A_MAP_VIEW].displayAll()#to prevent a black screen
		self.creature = creature
		self.creature.AIOverride(PlayerAI(self.creature))#override the ai
		self.updateToPlayerMove()
	def determineAction(self,keypressed,keyreleased,keytyped):
		if (keypressed.vk == L.KEY_NONE):#keypress handling
			return False
		move = (0,0)
		
		if (keyCommand("Move Left")):#movement
			move = (-1,0)
		if (keyCommand("Move Right")):
			move = (1,0)
		if (keyCommand("Move Down")):
			move = (0,1)
		if (keyCommand("Move Up")):
			move = (0,-1)
		if (keyCommand("Move Up Left")):
			move = (-1,-1)
		if (keyCommand("Move Up Right")):
			move = (1,-1)
		if (keyCommand("Move Down Left")):
			move = (-1,1)
		if (keyCommand("Move Down Right")):
			move = (1,1)
		if (keyCommand("Wait")):#wait
			return True#took a turn
		if (move != (0,0)):#movement
			if (not self.creature.move(move[0],move[1])):
				return False
			else:
				Game()[A_MAP_VIEW].scrolltoXY(self.creature.x-SCREEN_WIDTH/2,self.creature.y-SCREEN_HEIGHT/2)#scroll xy based on move
				return True
		else:
			return False#invalid key
	def updateToPlayerMove(self):#updates the time system to when the player can move
		if (self.creature.dead):#if dead
				return		
		while (not self.creature.ai.doMove):#basic time code
			Game()[A_MAP][L_CREATURES].tick()
			if (self.creature.dead):#if dead
				return
	def displayOverView(self):
		playerscreen.blitScreen()		
		if (self.creature.dead):#test message
			L.console_set_foreground_color(0,L.red)
			L.console_print_left(0,0,0,0,"You are dead!")
		for message in self.messages:#print message -- change later
			L.console_set_foreground_color(0,message[1])
			L.console_print_left(0,0,20,0,message[0])
		
	def receiveUI(self,keypressed,keyreleased,mouse):
		if (keypressed.vk == L.KEY_ESCAPE):#if Esc is pressed, restore the map
			Game()[A_UI_SWITCH](UI_MAP,"\\RESTORE")
			return
		if (not self.creature.dead and self.determineAction(keypressed,keyreleased,mouse)):#keep going if the creature is not dead and an action that costs a move has been determined
			self.creature.ai.doMove = False
			self.updateToPlayerMove()
			Game()[A_MAP_VIEW].displayCreatures()
			Game()[A_MAP_VIEW].displayView()
		
	def getUIConstant(self):
		return UI_CHAR
	
class MapUI(UIReader):
	cansave = True
	def __init__(self):
		self.paused = False
		self.pausescreen = PauseScreen()
		import Effect
		self.e = Effect.EffectsLayer()
		self.e.addMeleeAttackEffect(5,5,L.red)
	def receiveUI(self,keypressed,keyreleased,mouse):
		self.m = mouse
		if (not self.paused):#increment time when not paused
			for i in range(getConfig("TURNS PER FRAME")):#tick equivelent to the turns per frame
				Game()[A_MAP][L_CREATURES].tick()
			if (Game()[A_RNG].nextInt(0,30) == 0):
				Game()[A_MAP][L_CREATURES].applyGroupAIToFaction(GroupAI(Game()[A_RNG].nextInt(0,MAP_WIDTH-1),Game()[A_RNG].nextInt(0,MAP_HEIGHT-1)),1)
		if (self.m.rbutton_pressed):
			c = Game()[A_MAP][L_CREATURES][Point(viewtomapX(self.m.cx),viewtomapY(self.m.cy))]
			if (c != None):
				if (PLAYER_FACTION == c.faction):#can only control creatures of the same faction
				
					Game()[A_UI_SWITCH](UI_CHAR,c)
					return
				#attack creatures
				Game()[A_MAP][L_CREATURES].applyGroupAIToFaction(CreatureGroupAI(c),PLAYER_FACTION)
				return
			#if there is no creature, move all the creatures to a point
			Game()[A_MAP][L_CREATURES].applyGroupAIToFaction(GroupAI(viewtomapX(self.m.cx),viewtomapY(self.m.cy)),PLAYER_FACTION)	
		if (keyCommand("Begin Draw")):
			Game()[A_UI_SWITCH](UI_SELECTOR)
		if (keyCommand("Add Door")):
			if (Game()[A_MAP][L_TILES][Game()[A_MAP_VIEW].viewtomapX(self.m.cx)][Game()[A_MAP_VIEW].viewtomapY(self.m.cy)].getID() == TILE_WALL):
				Game()[A_MAP][L_TILES][Game()[A_MAP_VIEW].viewtomapX(self.m.cx)][Game()[A_MAP_VIEW].viewtomapY(self.m.cy)] = Door()
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Add Creature")):
			c = Creature()
			c.initCreature(viewtomapX(self.m.cx),viewtomapY(self.m.cy),'@',L.red)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Pause")):
			self.paused = not self.paused
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Fast Scroll Right")):#scrolling
			Game()[A_MAP_VIEW].scrollX(10)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Scroll Right")):
			Game()[A_MAP_VIEW].scrollX(1)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Fast Scroll Left")):
			Game()[A_MAP_VIEW].scrollX(-10)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Scroll Left")):
			Game()[A_MAP_VIEW].scrollX(-1)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Fast Scroll Up")):
			Game()[A_MAP_VIEW].scrollY(-10)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Scroll Up")):
			Game()[A_MAP_VIEW].scrollY(-1)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Fast Scroll Down")):
			Game()[A_MAP_VIEW].scrollY(10)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		if (keyCommand("Scroll Down")):
			Game()[A_MAP_VIEW].scrollY(1)
			Game()[A_MAP_VIEW].displayView()
			Game()[A_MAP_VIEW].displaySelections()
		Game()[A_MAP_VIEW].displayCreatures()#display the creature and selections
		
	def displayOverView(self):#display the selection over the view
		if (self.paused):
			pausescreen.blitScreen()
		self.e.updateEffects()
		self.e.drawEffects()
	def getUIConstant(self):
		return UI_MAP

class SelectionUI(UIReader):
	canSave = False
	def __init__(self):
		self.m = L.mouse_get_status()
		self.selection = 0#Selection(Point(Game()[A_MAP_VIEW].viewtomapX(self.m.cx),Game()[A_MAP_VIEW].viewtomapY(self.m.cy)))
		self.path = 0
		self.modifiable = False
		#self.updatePath()
	def updatePath(self):
		self.path = Line(self.selection.points[len(self.selection.points)-1],Point(Game()[A_MAP_VIEW].viewtomapX(self.m.cx),Game()[A_MAP_VIEW].viewtomapY(self.m.cy)))
	def displayOverView(self):#display the selection over the view
		drawscreen.blitScreen()
		mv = Game()[A_MAP_VIEW]
		L.console_clear(mv.selectiongraphics)
		mv.displaySelections()#display past selections
		if (self.modifiable):#display the current selection
			self.selection.displaySelection(L.red)
			if (len(self.path.points) > 0):
				p = self.path.points[len(self.path.points)-1]
				if (p.x != mv.viewtomapX(self.m.cx) or p.y != mv.viewtomapY(self.m.cy)):#if the points do not match
					self.updatePath()
				self.path.displaySelection(L.orange)
	def receiveUI(self,keypressed,keyreleased,mouse):
		self.m = mouse
		if (keyCommand("Finish Draw")):#finish the drawing
			if (self.modifiable):
				tmp = Plotarray()
				tmp.loadPoints(self.selection)
				del self.selection
				tmp.startfloodfill(isbuilt,False)
				Game()[A_MAP_VIEW].completedroomselections.append(tmp)
				Game()[A_MAP_VIEW].displayView()
				self.modifiable = False
		if (keyCommand("Stop Draw")):#stop the drawing
			Game()[A_UI_SWITCH](UI_MAP,"\\RESTORE")
			Game()[A_MAP_VIEW].displayAll()#update it
		if (keyCommand("Begin Draw")):#begin the drawing
			if (not self.modifiable):
				self.modifiable = True
			self.selection = Selection(Point(Game()[A_MAP_VIEW].viewtomapX(self.m.cx),Game()[A_MAP_VIEW].viewtomapY(self.m.cy)))
			self.updatePath()
		if (keyCommand("Fast Scroll Right")):#scrolling
			Game()[A_MAP_VIEW].scrollX(10)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Scroll Right")):
			Game()[A_MAP_VIEW].scrollX(1)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Fast Scroll Left")):
			Game()[A_MAP_VIEW].scrollX(-10)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Scroll Left")):
			Game()[A_MAP_VIEW].scrollX(-1)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Fast Scroll Up")):
			Game()[A_MAP_VIEW].scrollY(-10)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Scroll Up")):
			Game()[A_MAP_VIEW].scrollY(-1)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Fast Scroll Down")):
			Game()[A_MAP_VIEW].scrollY(10)
			Game()[A_MAP_VIEW].displayView()
		if (keyCommand("Scroll Down")):
			Game()[A_MAP_VIEW].scrollY(1)
			Game()[A_MAP_VIEW].displayView()
		if ((self.m.lbutton or self.m.lbutton_pressed)):
			if (self.modifiable):#add to the drawing
				mv = Game()[A_MAP_VIEW]
				self.selection.doPoint(Point(mv.viewtomapX(self.m.cx),mv.viewtomapY(self.m.cy)))
				self.updatePath()
			else:#select one of the drawings on the stack and fill it in
				xp = Game()[A_MAP_VIEW].viewtomapX(self.m.cx)#get x and y points
				yp = Game()[A_MAP_VIEW].viewtomapY(self.m.cy)
				for room in Game()[A_MAP_VIEW].completedroomselections:
					if (room.selectingAreaFloor(xp,yp)):#if selecting the floor
						room.implementSelection(fill,wall)#fill it in
						Game()[A_MAP_VIEW].displayView()
						Game()[A_MAP_VIEW].completedroomselections.remove(room)#remove the floor
		if (self.m.rbutton or self.m.rbutton_pressed):#delete the drawing
			xp = Game()[A_MAP_VIEW].viewtomapX(self.m.cx)#get x and y points
			yp = Game()[A_MAP_VIEW].viewtomapY(self.m.cy)
			for room in Game()[A_MAP_VIEW].completedroomselections:
				if (room.selectingAreaFloor(xp,yp)):#if selecting the floor
					Game()[A_MAP_VIEW].completedroomselections.remove(room)#remove the floor
	def getUIConstant(self):
		return UI_SELECTOR

class keyBindUI(UIReader):
	cansave = False
	rendermap = False
	def __init__(self):
		self.ychoicenum = 0#cursor for the key x and y binding position
		self.xchoicenum = 0
		self.xchoicemax = len(getStringsOfBinding(bindstrings[self.ychoicenum]))-1#get the x choice maximum
		self.enterkey = False#we are not entering a key
		self.keybind = None#used to bind keys
	def receiveUI(self,keypressed,keyreleased,mouse):
		L.console_set_background_color(0,L.Color(102,0,102))#purple
		L.console_set_foreground_color(0,L.Color(255,215,0))#gold
		L.console_print_center(0,SCREEN_WIDTH/2,0,0,"Key bindings")#headings
		L.console_print_center(0,SCREEN_WIDTH/2,1,0,"Press S to save")
		startprint = 2#start printing from the second line
		for key in bindstrings:#print all of the bound strings, key refers to a command
			if (startprint-2 == self.ychoicenum):
				if (not self.enterkey):#different color to show entering a new key
					L.console_set_foreground_color(0,L.Color(255,235,150))
				else:
					L.console_set_foreground_color(0,L.red)
			L.console_print_left(0,0,startprint,0,key)#print the command
			try:
				binding = getStringsOfBinding(key)[self.xchoicenum]
			except IndexError:#go to the farthest index if out of range
				binding = getStringsOfBinding(key)[len(getStringsOfBinding(key))-1]
			L.console_print_right(0,SCREEN_WIDTH-1,startprint,0,binding)#print the bound string
			startprint += 1#for loop within
			L.console_set_foreground_color(0,L.Color(255,215,0))#reset background
		if (not self.enterkey):#if not entering a key
			if (keypressed.c == ord('S')):#save the file
				saveConfigFile(KEYBINDINGS_PATH,saveKeyBinds())
			if (keyCommand("Menu Down")):#menu scrolling -- for up and down
				self.ychoicenum += 1#scroll y
				if (self.ychoicenum >= len(bindstrings)):
					self.ychoicenum = 0
				self.xchoicemax = len(getStringsOfBinding(bindstrings[self.ychoicenum]))-1#update and scroll x
				if (self.xchoicenum > self.xchoicemax):
					self.xchoicenum = self.xchoicemax
			elif (keyCommand("Menu Up")):
				self.ychoicenum -= 1
				if (self.ychoicenum < 0):
					self.ychoicenum = len(bindstrings)-1
				self.xchoicemax = len(getStringsOfBinding(bindstrings[self.ychoicenum]))-1
				if (self.xchoicenum > self.xchoicemax):
					self.xchoicenum = self.xchoicemax
			elif (keyCommand("Menu Left")):#left and right
				self.xchoicenum -= 1#scroll x, if able
				if (self.xchoicenum < 0):
					self.xchoicenum = self.xchoicemax
			elif (keyCommand("Menu Right")):
				self.xchoicenum += 1
				if (self.xchoicenum > self.xchoicemax):
					self.xchoicenum = 0
			elif (keyCommand("Menu Select")):#select from the menu
				self.enterkey = True#will allow the user to input keys
				self.keybind = keyBind()
			elif (keyCommand("Menu Back")):#go back to the title screen
				Game()[A_UI_SWITCH](UI_TITLE)
		else:#if entering a key
			if (self.keybind.setBindFromKeyPress(keypressed)):#if there is a valid combination
				setBinding(self.keybind, bindstrings[self.ychoicenum], self.xchoicenum)#set the binding
				self.keybind = None#go back to key browsing mode
				self.enterkey = False
	def getUIConstant(self):
		return UI_MAP
pausescreen = PauseScreen()
drawscreen = DrawScreen()
playerscreen = PlayerScreen()
